<!DOCTYPE html>
<html>

<head>

    <script type="module">

        // let Obj = {
        //     name: "亲",
        //     age: 18,
        //     label: "帅"
        // }

        // // let {name,age,label,height} = Obj;
        // // console.log("name:",name,"age:",age,"label",label,"height:",height);
        // //执行结果是：name: 亲 age: 18 label 帅 height: undefined

        // //位置对调，看看结果
        // let { age, name, height, label } = Obj;
        // console.log("name:", name, "age:", age, "label", label, "height:", height);

        // //////////////////////////////////////////////////////////////////////
        // // 分别用 apply，call，bind 来实现map函数功能
        // //////////////////////////////////////////////////////////////////////////
        // Array.prototype.map = function map() { // 参数可以认为有两个 this,arguments
        //     alert(this);
        //     let myfun1 = arguments[0];
        //     let resultArray = [];
        //     for (let value of this) {
        //         resultArray.push(myfun1(value));
        //     }
        //     return resultArray;
        // }

        // let mydelegate = function mydelegate(x) {
        //     alert(x);
        //     return x * x;
        // }

        // //   console.log(Array.prototype.map.apply([1, 2, 3], [mydelegate])) ;
        // // console.log(Array.prototype.map.call([1, 2, 3], mydelegate)) ;
        // console.log(Array.prototype.map.bind([1, 2, 3], mydelegate)());

        // // console.log([1, 2, 3].map(x => x * x));
        // //console.log([1, 2, 3].map(mydelegate));


        // // [1, 2, 3] 是Array类的实例
        // // [1, 2, 3].__proto__===Array.prototype


        Function.prototype.myCall = function (context, ...args) {
            // 判断调用对象
            if (typeof this !== "function") {
                console.error("type error");
            }
            // 判断 context 是否传入，如果未传入则设置为 window
            context = context || window;
            // 将调用函数设为对象的方法
            context.fn = this;
            // 调用方法
            const result = (args === undefined || args === null) ? context.fn() : context.fn(...args);
            // 将属性删除
            delete context.fn;
            return result;
        };

        const foo = {
            name: 'hello',
            logName: function (...args) {
                console.log(args, 111);
                console.log(this.name, 333);
            }
        }
        const bar = {
            name: 'world'
        }
        console.log(foo.logName.myCall(bar, '1', '2'), 'res');


        Function.prototype.myApply = function (context, args) {
            // 判断调用对象
            if (typeof this !== "function") {
                console.error("type error");
            }
            // 判断 context 是否传入，如果未传入则设置为 window
            context = context || window;
            // 将调用函数设为对象的方法
            context.fn = this;
            // 调用方法
            const result = (args === undefined || args === null) ? context.fn() : context.fn(...args);
            // 将属性删除
            delete context.fn;
            return result;
        };

        console.log(foo.logName.myApply(bar), 'res');

        // /*
        // ctx: 传入的对象，
        // */
        // Function.prototype.myBind = function (ctx, ...args) {
        //     // 判断调用对象
        //     if (typeof this !== "function") {
        //         console.error("type error");
        //     }
        //     // 判断 context 是否传入，如果未传入则设置为 window
        //     ctx = ctx || window;
        //     // 将调用函数设为对象的方法
        //     ctx.fn = this;// 传入的对象上绑定一个临时方法，这个临时方法指向this（就是外部○○.mybind 中○○代表的方法）
        //     return function () {
        //         // 调用方法
        //         const result = (args === undefined || args === null) ? ctx.fn() : ctx.fn(...args);
        //         // 将属性删除
        //         delete ctx.fn;// 防止传入的对象被污染！
        //         return result;
        //     };
        // }


        Function.prototype.myBind = function (context, ...args) {
            // 把方法取出来
            const fn = this
            args = args || []
            return function newFn(...newFnArgs) {
                // 1. 作为构造函数
                if (this instanceof newFn) {
                    return new fn(...args, ...newFnArgs)
                }
                // 2. 普通函数直接调用
                return fn.apply(context, [...args, ...newFnArgs])
            }
        };

        let obj = {
            age: 18,
            getAge: function (name, job) {
                this.name = name;
                this.job = job
                console.log(name + '现在' + this.age + '岁,' + '工作是' + job);
            }
        }
        obj.age = 20
        let _fn = obj.getAge
        // 作为构造函数时
        let newObj = _fn.myBind(obj)
        let o = new newObj('小红', '外卖小哥')
        console.log(o);

        // 作为函数调用时
        _fn.myBind(obj)('小红', '直播网红')



    </script>
</head>

<body>

    <div id="mydiv"></div>

</body>

</html>